编写模板时，规则性是一种优点:若单一构造可以覆盖所有情况，会使模板更简单。我们的程序有一点不规则，那就是类型。例如，考虑以下情况:

\begin{lstlisting}[style=styleCXX]
auto&& r = f(); // error if f() returns void
\end{lstlisting}

这适用于f()返回的所有类型，除了void。同样的问题发生在使用decltype(auto):

\begin{lstlisting}[style=styleCXX]
decltype(auto) r = f(); // error if f()
\end{lstlisting}

void并不是唯一的非规范类型:函数类型和引用类型在某些方面也经常出现异常行为。然而，void会使模板变得复杂。例如，第11.1.3节如何使完美的std::invoke()包装器实现复杂化的示例。

可以将void定义为具有唯一值的普通值类型(如std::nullptr\_t表示nullptr)。为了向后兼容的目的，仍需要为函数声明保留一个特殊的情况:

\begin{lstlisting}[style=styleCXX]
void g(void); // same as void g();
\end{lstlisting}

在大多数方式中，void会成为一个完整的值类型。可以声明void变量和引用:

\begin{lstlisting}[style=styleCXX]
void v = void{};
void&& rrv = f();
\end{lstlisting}

更重要的是，许多模板不再需要专门处理void。













































